package db

import "encoding/binary"

// Entry Header Size
const (
	entryHeaderSize     = 14
	hintentryHeaderSize = 24
)

// Mark
const (
	PUT uint16 = iota
	DEL
)

// Entry 写入文件的记录
type Entry struct {
	Key       []byte
	Value     []byte
	KeySize   uint32
	ValueSize uint32
	Timestamp uint32
	//TTL       uint32
	Mark uint16
}
type HintEntry struct {
	Key       []byte
	KeySize   uint32
	ValueSize uint32
	ValuePos  uint64
	FileId    uint32
	Timestamp uint32
}

// NewEntry 创建一个新的 Entry
func NewEntry(key, value []byte, mark uint16, time uint32) *Entry {
	return &Entry{
		Key:       key,
		Value:     value,
		KeySize:   uint32(len(key)),
		ValueSize: uint32(len(value)),
		Mark:      mark,
		Timestamp: time,
		//TTL:       ttl,
	}
}

// NewHintEntry 创建一个新的 HintEntry
func NewHintEntry(key []byte, keySize, valueSize, timeStamp uint32, index uint64, fileId uint32) *HintEntry {
	return &HintEntry{
		Key:       key,
		KeySize:   keySize,
		ValueSize: valueSize,
		Timestamp: timeStamp,
		ValuePos:  index,
		FileId:    fileId,
	}
}

// GetSize 获取 Entry 的大小
func (e *Entry) GetSize() int64 {
	return int64(entryHeaderSize + e.KeySize + e.ValueSize)
}

// GetSize 获取 HintEntry 的大小
func (e *HintEntry) GetSize() int64 {
	return int64(hintentryHeaderSize + e.KeySize)
}

// Encode 编码 Entry，返回字节数组
func (e *Entry) Encode() ([]byte, error) {
	buf := make([]byte, e.GetSize())
	binary.BigEndian.PutUint32(buf[0:4], e.KeySize)
	binary.BigEndian.PutUint32(buf[4:8], e.ValueSize)
	binary.BigEndian.PutUint32(buf[8:12], e.Timestamp)
	binary.BigEndian.PutUint16(buf[12:14], e.Mark)
	copy(buf[entryHeaderSize:entryHeaderSize+e.KeySize], e.Key)
	copy(buf[entryHeaderSize+e.KeySize:], e.Value)
	return buf, nil
}

// Decode entry结构
/*
|keySize|valueSize|timestamp|mark|key|value|
|4B    |4B       |4B        |2B  |keySize|valueSize|
*/
// Decode 解码 buf 字节数组，返回 Entry
func Decode(buf []byte) (*Entry, error) {
	ks := binary.BigEndian.Uint32(buf[0:4])
	vs := binary.BigEndian.Uint32(buf[4:8])
	timestamp := binary.BigEndian.Uint32(buf[8:12])
	mark := binary.BigEndian.Uint16(buf[12:14])
	return &Entry{KeySize: ks, ValueSize: vs, Mark: mark, Timestamp: timestamp}, nil
}

// HintEncode 编码 HintEntry，返回字节数组
func (e *HintEntry) HintEncode() ([]byte, error) {
	buf := make([]byte, e.GetSize())
	binary.BigEndian.PutUint32(buf[0:4], e.Timestamp)
	binary.BigEndian.PutUint32(buf[4:8], e.KeySize)
	binary.BigEndian.PutUint32(buf[8:12], e.ValueSize)
	binary.BigEndian.PutUint32(buf[12:16], e.FileId)
	binary.BigEndian.PutUint64(buf[16:24], e.ValuePos)
	copy(buf[hintentryHeaderSize:hintentryHeaderSize+e.KeySize], e.Key)
	return buf, nil
}

// HintDecode entry结构
/*
|timestamp|keySize|valueSize|fileId|valuePos|key|
|4B       |4B     |4B       |4B    |8B      |keySize|
*/
func HintDecode(buf []byte) (*HintEntry, error) {
	timestamp := binary.BigEndian.Uint32(buf[0:4])
	ks := binary.BigEndian.Uint32(buf[4:8])
	vs := binary.BigEndian.Uint32(buf[8:12])
	fd := binary.BigEndian.Uint32(buf[12:16])
	vp := binary.BigEndian.Uint64(buf[16:24])
	return &HintEntry{Timestamp: timestamp, KeySize: ks, ValueSize: vs, ValuePos: vp, FileId: fd}, nil
}
